/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kurvykurvy.image;

import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.event.EventListenerList;
import org.openide.util.Exceptions;

/**
 *
 * @author HY
 */
public class ImageLoader
{
    public static final String NEW_FILE = "new_file";
    public static final String REMOVED_FILE = "removed_file";

    static ImageLoader DEFAULT_INSTANCE;
    Vector<LoadedImage> loadedImages;

    Vector<File> queuedFiles;

    int threadLimit = 5;
    ThreadGroup imageLoaderGroup;
    Timer keepAlive;

    EventListenerList eventListeners;

    private ImageLoader()
    {
        imageLoaderGroup = new ThreadGroup( "ImageLoaderThreads" );
        imageLoaderGroup.setMaxPriority( Thread.MIN_PRIORITY );
        keepAlive = new Timer( "KeepAlive", true );
        keepAlive.schedule(
            new TimerTask()
            {
                @Override
                public void run()
                {
                    System.out.println( "Image Loader Group Active : " + imageLoaderGroup.activeCount() );
                    if( imageLoaderGroup.activeCount() < threadLimit )
                    {
                        loadQueuedFiles();
                    }
                }
            },
            0,
            5000
        );
    }

    public static ImageLoader getInstance()
    {
        if( DEFAULT_INSTANCE == null )
            DEFAULT_INSTANCE = new ImageLoader();

        return DEFAULT_INSTANCE;
    }

    public void loadImage( File src )
        throws IOException
    {
        queueLoad( src );
        loadQueuedFiles();
    }

    public void addImage( LoadedImage img )
    {
        if( loadedImages == null )
            loadedImages = new Vector<LoadedImage>();

        loadedImages.add( img );

        if( this.queuedFiles != null && !this.queuedFiles.isEmpty() )
        {
            loadQueuedFiles();
        }

        PropertyChangeEvent evt = new PropertyChangeEvent( this, NEW_FILE, null, img );
        firePropertyChange( evt );
    }

    public void addImage( BufferedImage img )
    {
        if( loadedImages == null )
            loadedImages = new Vector<LoadedImage>();

        loadedImages.add( new LoadedImage( img ) );
        
        PropertyChangeEvent evt = new PropertyChangeEvent( this, NEW_FILE, null, img );
        firePropertyChange( evt );
    }

    public void removeImage( LoadedImage img )
    {
        if( loadedImages != null )
        {
            loadedImages.remove( img );

            PropertyChangeEvent evt = new PropertyChangeEvent( this, REMOVED_FILE, null, img );
            firePropertyChange( evt );

        }
    }

    public void removeImage( BufferedImage img )
    {
        if( loadedImages != null )
        {
            loadedImages.remove( img );

            PropertyChangeEvent evt = new PropertyChangeEvent( this, REMOVED_FILE, null, img );
            firePropertyChange( evt );
        }
    }

    public Vector<LoadedImage> getImages()
    {
        if( loadedImages == null )
            loadedImages = new Vector<LoadedImage>();

        return (Vector<LoadedImage>) loadedImages.clone();
    }

    protected boolean loadFile( final File src )
    {
        boolean result = false;
        if( imageLoaderGroup.activeCount() < threadLimit )
        {
            Runnable runnable = new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {
                        LoadedImage loadedImage = new LoadedImage( src );
                        ImageLoader.getInstance().addImage( loadedImage );
                        ImageLoader.getInstance().loadQueuedFiles();
                        Thread.sleep( 100 );
                        Thread.yield();
                    }
                    catch ( IOException ex )
                    {
                        Exceptions.printStackTrace( ex );
                    }
                    catch( InterruptedException irEx )
                    {
                        Exceptions.printStackTrace( irEx );
                    }
                }
            };
            Thread newThread = new Thread( imageLoaderGroup, runnable );
            newThread.start();
            System.out.println( "Image Loader Group Active Count : " + imageLoaderGroup.activeCount() );
            result = true;
        }
        return result;
    }

    protected void loadQueuedFiles()
    {
        if( this.queuedFiles != null && !this.queuedFiles.isEmpty() )
        {
            for( Iterator<File> it = this.queuedFiles.iterator(); it.hasNext(); )
            {
                File f = it.next();
                boolean initiatedLoad = loadFile( f );
                if( initiatedLoad )
                {
                    it.remove();
                }
                else
                {
                    break;
                }
            }
        }
    }

    protected void queueLoad( File src )
    {
        if( this.queuedFiles == null )
            this.queuedFiles = new Vector<File>();

        this.queuedFiles.add( src );
    }

    public void firePropertyChange( PropertyChangeEvent evt )
    {
        if( eventListeners != null )
        {
            PropertyChangeListener[] listeners = eventListeners.getListeners( PropertyChangeListener.class );
            for( int i = 0; i < listeners.length; i++ )
            {
                listeners[ i ].propertyChange( evt );
            }
        }
    }

    public void addPropertyChangeListener( PropertyChangeListener l )
    {
        if( eventListeners == null )
            eventListeners = new EventListenerList();

        this.eventListeners.add( PropertyChangeListener.class, l);
    }

    public void removePropertyChangeListener( PropertyChangeListener l )
    {
        if( eventListeners != null )
        {
            eventListeners.remove(  PropertyChangeListener.class, l);
        }
    }
}
